Skip to content

Add EquatableAnalyzer diagnostic analyzer for collection/attribute validation#129

Merged
pwelter34 merged 3 commits intomainfrom
copilot/add-diagnostic-analyzer
Apr 3, 2026
Merged

Add EquatableAnalyzer diagnostic analyzer for collection/attribute validation#129
pwelter34 merged 3 commits intomainfrom
copilot/add-diagnostic-analyzer

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 2, 2026

  • Add new diagnostic descriptors EQ0001 and EQ0002 for missing collection/dictionary equality attributes
  • Create EquatableAnalyzer.cs as a DiagnosticAnalyzer
  • Add EquatableAnalyzerTest.cs with tests for all diagnostic cases
  • Fix AllInterfaces bug: Added ImplementsDictionary(ITypeSymbol) and ImplementsEnumerable(ITypeSymbol) helpers that check if the type IS the interface itself OR implements it — fixes false positives/negatives for IDictionary<,>/IEnumerable<T>-typed properties
  • Walk base types: Replaced inline GetMembers() with GetAnalyzableProperties() that walks the base type chain (de-duplicating by name, matching generator behavior), stopping at Object/ValueType or at an [Equatable] base type
  • Fix double spaces in DiagnosticDescriptors.cs message format strings (EQ0010–EQ0013)
  • Add interface-typed property tests: IDictionary<,>, IEnumerable<T>, IReadOnlyCollection<T> missing-attribute; valid [DictionaryEquality]/[SequenceEquality] on interface types; base-type inclusion/exclusion tests
  • All 88 tests pass, 0 warnings, 0 CodeQL alerts

…ing collection attributes and EQ0010-EQ0013 for invalid attribute usage

Agent-Logs-Url: https://github.com/loresoft/Equatable.Generator/sessions/00bd26b4-cc86-4bf1-a638-e609fc955d18

Co-authored-by: pwelter34 <1196837+pwelter34@users.noreply.github.com>
Copilot AI changed the title [WIP] Add diagnostic analyzer for source generator warnings Add EquatableAnalyzer diagnostic analyzer for collection/attribute validation Apr 2, 2026
Copilot AI requested a review from pwelter34 April 2, 2026 18:42
@pwelter34 pwelter34 requested a review from Copilot April 2, 2026 18:50
@pwelter34 pwelter34 marked this pull request as ready for review April 2, 2026 18:50
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a Roslyn DiagnosticAnalyzer for the Equatable source generator to report missing/invalid equality attributes on properties of [Equatable] types, keeping these diagnostics out of the generator pipeline.

Changes:

  • Introduces EquatableAnalyzer with diagnostics for missing collection/dictionary attributes and invalid attribute usage.
  • Adds new diagnostic descriptors EQ0001/EQ0002 and refines message formatting for existing EQ0010-EQ0013.
  • Adds an analyzer-focused test suite validating expected diagnostics and non-diagnostics.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
src/Equatable.SourceGenerator/EquatableAnalyzer.cs Implements the new analyzer logic and emits diagnostics based on property types/attributes.
src/Equatable.SourceGenerator/DiagnosticDescriptors.cs Adds new descriptors for missing attributes and updates message formats for existing descriptors.
test/Equatable.Generator.Tests/EquatableAnalyzerTest.cs Adds unit tests to validate analyzer behavior across valid, invalid, and missing-attribute scenarios.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +37 to +47
var properties = typeSymbol
.GetMembers()
.OfType<IPropertySymbol>()
.Where(p => !p.IsIndexer
&& p.DeclaredAccessibility == Accessibility.Public
&& !IsIgnored(p));

foreach (var property in properties)
AnalyzeProperty(context, property);
}

Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AnalyzeNamedType only analyzes properties returned from typeSymbol.GetMembers(), so diagnostics won’t be produced for public properties declared on base types—even though the source generator can include base properties (see EquatableGenerator.GetProperties(...) looping currentSymbol = currentSymbol.BaseType). To keep analyzer feedback aligned with generated equality behavior, consider walking base types with similar include/exclusion rules (and de-duping by property name).

Suggested change
var properties = typeSymbol
.GetMembers()
.OfType<IPropertySymbol>()
.Where(p => !p.IsIndexer
&& p.DeclaredAccessibility == Accessibility.Public
&& !IsIgnored(p));
foreach (var property in properties)
AnalyzeProperty(context, property);
}
foreach (var property in GetAnalyzableProperties(typeSymbol))
AnalyzeProperty(context, property);
}
private static IEnumerable<IPropertySymbol> GetAnalyzableProperties(INamedTypeSymbol typeSymbol)
{
var seenPropertyNames = new System.Collections.Generic.HashSet<string>(System.StringComparer.Ordinal);
for (var currentSymbol = typeSymbol; currentSymbol != null; currentSymbol = currentSymbol.BaseType)
{
foreach (var property in currentSymbol
.GetMembers()
.OfType<IPropertySymbol>()
.Where(p => !p.IsIndexer
&& p.DeclaredAccessibility == Accessibility.Public
&& !IsIgnored(p)))
{
if (seenPropertyNames.Add(property.Name))
yield return property;
}
}
}

Copilot uses AI. Check for mistakes.
@pwelter34
Copy link
Copy Markdown
Member

@copilot apply changes based on the comments in this thread

…uble spaces, add interface-typed property tests

Agent-Logs-Url: https://github.com/loresoft/Equatable.Generator/sessions/5b8943ea-bd6f-4681-8ca8-834635a97745

Co-authored-by: pwelter34 <1196837+pwelter34@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 2, 2026

@copilot apply changes based on the comments in this thread

Applied all review changes in commit 14eb437:

  1. AllInterfaces bug (EQ0011/EQ0013 false positives) — Added ImplementsDictionary(ITypeSymbol) and ImplementsEnumerable(ITypeSymbol) helpers that check type is INamedTypeSymbol named && IsDictionary/IsEnumerable(named) OR type.AllInterfaces.Any(...). Both the attribute-validation and the missing-attribute branches now use these helpers.

  2. Base-type property walking — Replaced the inline GetMembers() query with a GetAnalyzableProperties() iterator that walks the base type chain (de-duplication by name, matching the generator's GetProperties logic), stopping at Object/ValueType or at a base type that itself has [Equatable] (to avoid double-warning for properties that are analyzed when the base type is processed).

  3. Double spaces in message strings — Fixed '. Property''. Property' in DiagnosticDescriptors.cs for EQ0010–EQ0013.

  4. Interface-typed property tests — Added 7 new tests: IDictionary<,> and IEnumerable<T>/IReadOnlyCollection<T> missing-attribute; valid [DictionaryEquality] on IDictionary<,> and [SequenceEquality] on IEnumerable<T> (no false positives); and base-type property inclusion/exclusion based on whether the base has [Equatable].

All 88 tests pass, 0 build warnings, 0 CodeQL alerts.

@pwelter34 pwelter34 merged commit ad6d546 into main Apr 3, 2026
7 checks passed
@pwelter34 pwelter34 deleted the copilot/add-diagnostic-analyzer branch April 3, 2026 00:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants